home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / pctchnqs / 1990 / number5 / msg_pckt.cpp < prev    next >
C/C++ Source or Header  |  1990-10-06  |  11KB  |  264 lines

  1. /****************************************************************
  2. *   MSG_PCKT.CPP - Listing 6
  3. *   Written by Kevin D. Weeks, August 1990
  4. *   Compiles and runs under Borland Turbo C++ and Zortech C++.
  5. */
  6. #if defined(__TURCOC__)
  7.     #include <mem.h>            // memset() prototype in Turbo
  8. #else
  9.     #include <string.h>         // memset() prototype in Zortech
  10. #endif
  11. #include "msg_pckt.hpp"
  12. // timer function codes
  13. #define MARK    1
  14. #define ELAPSED 2
  15. // protocol codes
  16. #define ACK     6
  17. #define NAK     21
  18. // these two functions are not part of the class but are included
  19. // here for convenience.
  20. unsigned int  timer(int function);
  21. unsigned int  calc_crc(void *buffer, int length);
  22. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  23. *   Null constructor - the difference between this constructor and
  24. *   the next one is the use of Serial_Comm's default parameters.  */
  25. Msg_Packet::Msg_Packet(void) : Serial_Comm()
  26. {
  27.     timeout = 50;
  28.     re_trys = 3;
  29.     memset(&recv_msg_buffer,'\0',sizeof(recv_msg_buffer));
  30.     memset(&send_msg_buffer,'\0',sizeof(send_msg_buffer));
  31.     // initialize the buffer size to the default plus the other
  32.     // packet members
  33.     Serial_Comm::set_buffer_size(DEFAULT_BUF_SIZE + sizeof(Msg_Type) +
  34.                     sizeof(char *) + sizeof(int));
  35.     status.type_read = status.size_read = status.msg_read = FALSE;
  36. }
  37. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  38. *   Constructor - communication parameters are specified.           */
  39. Msg_Packet::Msg_Packet(Com_Port port, Baud_Rate baud, Parity par,
  40.                        Stop_Bits stop, Data_Bits data) :
  41.                        Serial_Comm(port,baud,par,stop,data)
  42. {
  43.     timeout = 50; re_trys = 3;
  44.     memset(&recv_msg_buffer,'\0',sizeof(recv_msg_buffer));
  45.     memset(&send_msg_buffer,'\0',sizeof(send_msg_buffer));
  46.     // initialize the buffer size to the default plus the other
  47.     // packet members
  48.     Serial_Comm::set_buffer_size(DEFAULT_BUF_SIZE + sizeof(Msg_Type) +
  49.                     sizeof(char *) + sizeof(int));
  50.     status.type_read = status.size_read = status.msg_read = FALSE;
  51. }
  52. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  53. *   Provides support for message type and size. Will not return until
  54. *   either a message is received, or the timeout or retry values have
  55. *   been exceeded.                                                  */
  56. Result  Msg_Packet::read(Msg_Type *type, int *msg_size, void *buffer)
  57. {
  58.     int     bytes_read;
  59.     *type = get_recv_msg_type();
  60.     if ((*type == MSG_ERROR) || (*type == NO_MESSAGE))
  61.         return ERROR;
  62.     *msg_size = get_recv_msg_size();
  63.     get_recv_message(buffer);
  64.     status.type_read = status.size_read = status.msg_read = FALSE;
  65.     recv_msg_buffer.type = NO_MESSAGE;
  66.     recv_msg_buffer.length = 0;
  67.     return OK;
  68. }
  69. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  70. *   Provides support for message type and size. Will not return until
  71. *   the message is ACKnowledged or the retry and timeout values have
  72. *   been exceeded.                                                  */
  73. Result  Msg_Packet::write(Msg_Type type, int msg_size, void *buffer)
  74. {
  75.     set_send_msg_type(type);
  76.     if (set_send_msg_size(msg_size) == ERROR)
  77.         return ERROR;
  78.     set_send_message(buffer);
  79.     return send_message();
  80. }
  81. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  82. *   Returns the message type. If the type has already been read it is
  83. *   returned immediately, otherwise this method waits for up to
  84. *   timeout tenths of a second for a message to be received.        */
  85. Msg_Type    Msg_Packet::get_recv_msg_type(void)
  86. {
  87.     Msg_Type    ret_value;
  88.     if (open_flag != this) return NO_MESSAGE;
  89.     if (status.type_read == TRUE)   // type already acquired. return it.
  90.         return recv_msg_buffer.type;
  91.     timer(MARK);                    // start the timer
  92.     do {                    // loop until type is received or timeout
  93.         if (com_chars_recvd() >= 2) {   // check for word size type
  94.             // first read the message type low byte
  95.             if ((recv_msg_buffer.type =
  96.                     (Msg_Type)com_read_char()) == ERROR)
  97.                 break;
  98.             com_read_char();        // throw away the high byte
  99.             status.type_read = TRUE;
  100.             return recv_msg_buffer.type;
  101.         }
  102.     } while (timer(ELAPSED) < timeout);
  103.     recv_msg_buffer.type = NO_MESSAGE;
  104.     return MSG_ERROR;
  105. }
  106. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  107. *   Returns the message size. If the size has already been read it is
  108. *   returned immediately, otherwise this method waits for up to
  109. *   timeout tenths of a second for a message to be received.        */
  110. int     Msg_Packet::get_recv_msg_size(void)
  111. {
  112.     int     ret_value;
  113.     if (open_flag != this) return (int)ERROR;
  114.     // if the type hasn't been read yet, read it
  115.     if (get_recv_msg_type() == MSG_ERROR) return (int)ERROR;
  116.     // if the size has already been read return it
  117.     if (status.size_read == TRUE)
  118.         return (recv_msg_buffer.length);
  119.     timer(MARK);                            // start the timer
  120.     do {                    // loop until size is received or timeout
  121.         if (com_chars_recvd() >= 2) {       // size is two bytes long
  122.             if ((recv_msg_buffer.length = com_read_char()) == ERROR)
  123.                 break;
  124.             if ((ret_value = com_read_char()) == ERROR) break;
  125.             recv_msg_buffer.length &= ret_value << 8;
  126.             status.size_read = TRUE;
  127.             return recv_msg_buffer.length;
  128.         }
  129.     } while (timer(ELAPSED) < timeout);
  130.     recv_msg_buffer.type = MSG_ERROR;
  131.     return (int)ERROR;
  132. }
  133. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  134. *   Return the message received. This methods will try up to re_trys
  135. *   times to read a message. Once successfully read the message is re-
  136. *   turned but not destroyed.                                       */
  137. Result  Msg_Packet::get_recv_message(void *buffer)
  138. {
  139.     int             retry_counter = 0;
  140.     int             ret_value;
  141.     int             bytes_read;
  142.     unsigned int    crc;
  143.     if (open_flag != this) return ERROR;
  144.     // if the message has already been read then just return it
  145.     if (status.msg_read) {
  146.         memcpy(buffer,recv_msg_buffer.msg,recv_msg_buffer.length);
  147.         return OK;
  148.     }
  149.             // loop until either a complete message has
  150.     do {    //  been read or until re_trys is exceeded.
  151.         // get the message type
  152.         if (get_recv_msg_type() != MSG_ERROR)
  153.             if (get_recv_msg_size() != -1){ // get the message size
  154.                 timer(MARK);                // start the timer
  155.                 bytes_read = 0;
  156.                 do {
  157.                     if ((ret_value = com_read
  158.                     (&recv_msg_buffer.msg[bytes_read])) == ERROR)
  159.                         break;
  160.                     else {
  161.                         bytes_read += ret_value;
  162.                         if (bytes_read >= recv_msg_buffer.length) {
  163.                             // add 4 to allow for type & size
  164.                             crc = calc_crc(&recv_msg_buffer,
  165.                                 recv_msg_buffer.length + 4);
  166.                             if (crc == (unsigned int) recv_msg_buffer
  167.                                       .msg[recv_msg_buffer.length]) {
  168.                                 com_write_char(ACK);
  169.                                 status.msg_read = TRUE;
  170.                                 memcpy(buffer,recv_msg_buffer.msg,
  171.                                     recv_msg_buffer.length);
  172.                                 return OK;
  173.                             } else {
  174.                                 com_write_char(NAK);
  175.                                 status.type_read = FALSE;
  176.                                 status.size_read = FALSE;
  177.                             }
  178.                         }
  179.                     }
  180.                 } while (timer(ELAPSED) < timeout);
  181.             }
  182.     } while (++retry_counter < re_trys);
  183.     status.type_read = status.size_read = status.msg_read = FALSE;
  184.     return ERROR;
  185. }
  186. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  187. *   Sets the size of the message to be sent.                        */
  188. Result  Msg_Packet::set_send_msg_size(int size)
  189. {
  190.     if (size <= get_buffer_size()) {
  191.         send_msg_buffer.length = size;
  192.         return OK;
  193.     }
  194.     return ERROR;
  195. }
  196.  
  197. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  198. Result  Msg_Packet::send_message(void)
  199. {
  200.     int             response;
  201.     int             retry_counter;
  202.     unsigned int    t;
  203.     if (send_msg_buffer.type == NO_MESSAGE) return ERROR;
  204.     // calculate the crc
  205.     send_msg_buffer.msg[send_msg_buffer.length] =
  206.               calc_crc(&send_msg_buffer,send_msg_buffer.length + 4);
  207.     // if we're currently sending wait until the current mesage is out
  208.     timer(MARK);
  209.     while (get_status().flag.sending_message)
  210.         if (timer(ELAPSED) > timeout) return ERROR;
  211.     // loop until the mesage has been sent or retrys has been exceeded
  212.     do {
  213.         if ((Result)com_write(send_msg_buffer.length + 6,
  214.                               &send_msg_buffer) != ERROR) {
  215.             // wait until the message is gone
  216.             timer(MARK);
  217.             while (get_status().flag.sending_message)
  218.                 if (timer(ELAPSED) > timeout) return ERROR;
  219.             // now wait until the ACK or NAK is received
  220.             timer(MARK);
  221.             while (!get_status().flag.char_received)
  222.                 if (timer(ELAPSED) > timeout) break;
  223.             if (get_status().flag.char_received) {
  224.                 response = com_read_char();
  225.                 if (response == ACK) return OK;
  226.             }
  227.         }
  228.     } while (++retry_counter < re_trys);
  229.     return ERROR;
  230. }
  231. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  232. *   This function is not a member of Msg_Packet. The clock is started
  233. *   when it is passed the MARK code. Thereafter it returns (approxima-
  234. *   tely) the number of tenths of a second that have passed since MARK
  235. */
  236. unsigned int timer(int function)
  237. {
  238.     static long     reference;
  239.     static long far *bios_clock = (long far *)0x0040006c;
  240.     if (function == MARK) reference = *bios_clock;
  241.     return (unsigned int)((*bios_clock - reference) / 2);
  242. }
  243. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  244. *   This function is also not a member of Msg_Packet. It calculates a
  245. *   CRC value which is then used to detect message corruption.      */
  246. unsigned int    calc_crc(unsigned char *buffer, int length)
  247. {
  248.     unsigned int    cur_crc;
  249.     int             i, j;
  250.     for (i = 0; i < length; i++) {
  251.         // xor current byte with crc hi-byte
  252.         cur_crc ^= (unsigned int)*buffer << 8;
  253.         // shift crc left 8 times checking to see if MSB is on
  254.         for (j = 0; j < 8; j++)
  255.             if (cur_crc & 0x8000)           // if MSB on
  256.                 // shift left and xor with prime
  257.                 cur_crc = (cur_crc << 1) ^ 0x1021;
  258.             else
  259.                 cur_crc <<= 1;              // just shift left
  260.         ++buffer;
  261.     }
  262.     return cur_crc;
  263. }
  264.